#include "ActionNotify.h"
#include "util.h"
#include "streamdata.h"
#include "agency_event_service.h"
#include "agencyeventmgr.h"
#include "9200_agency_event_api.pb.h"
#include "9100_agency_api.pb.h"
#include "account_service.h"

static std::map<std::string,std::string> http_json_heads = {{"Content-Type","application/json"}};

static bool __init__ = ActionNotify::Init();
const int NOTIFY_MAX_USER_NUM = 500;
bool ActionNotify::Init()
{
    Ctx.msg_router.BindMsg(agency_event_api::AGENCY_EVENT_API_MSGID_NOTIFY_REQ, ActionNotify::Handle);
    AgencyEventService::Instance()->ListenOnAgencyEventGet(AgencyEventService::NOTIFY, ActionNotify::OnAgencyEventGet);
    AccountService::Instance()->ListenOnAccountGet(AccountService::NOTIFY, ActionNotify::OnAccountGet);
    return true;
}

void ActionNotify::Handle(MsgData&& msg_data)
{
    agency_event_api::NotifyReq req;

    do {
        if (!req.ParseFromArray(msg_data.data.data(), msg_data.data.size()))
        {
            log_error("parser agency_event_api::NotifyReq failed");
            break;
        }
        log_debug("req:%s", req.ShortDebugString().c_str());

        Json::Value data_json;
        data_json["data"] = req.data();
        data_json["game"] = req.game();
        data_json["type"] = req.type();
        std::string json_string = CTools::ToStr(data_json);

        std::map<int, std::vector<std::string>> map_userName;
        for (auto i = 0; i < req.userinfo_size(); i++)
        {
            if (req.userinfo(i).username().size() <= 0 || req.userinfo(i).agencyid() <= 0)
            {
                //去account服中取
                uint32_t uid = req.userinfo(i).uid();
                log_debug("not found uid data need to account found! uid = %d", uid);
                //account_proto::ACCOUNT_CMD_GET_ACCOUNT_REQ:
                const Account* pAccount = AccountMgr::Instance()->GetAccount(uid);
                if (pAccount != nullptr)
                {
                    log_debug("内存中找到了! uid = %d, username = %s, agencyid = %d", uid, pAccount->username.c_str(), pAccount->agencyid);
                    map_userName[pAccount->agencyid].push_back(pAccount->username);
                }
                else
                {
                    StreamData stream_data;
                    StreamDataWriter writer(stream_data);
                    writer.WriteShort(msg_data.svtype);
                    writer.WriteInt(msg_data.svid);
                    writer.WriteInt(msg_data.uuid);
                    writer.WriteInt(uid);
                    writer.WriteString(json_string);

                    if (!AccountService::Instance()->HandleGetAccount(uid, std::move(stream_data.Data()), AccountService::NOTIFY))
                    {
                        log_error("HandleGetAccount failed,uid:%u", uid);
                        break;
                    }
                }
            }
            else
            {
                map_userName[req.userinfo(i).agencyid()].push_back(req.userinfo(i).username());
            }
        }

        for (auto &pair:map_userName)
        {
            Json::Value username_json;
            for (auto i = 0; i < pair.second.size(); i++)
            {
                username_json.append(pair.second[i]);
            }
            data_json["usernameArr"] = username_json;

            json_string = CTools::ToStr(data_json);

            OnAgencyEventGetInc(pair.first, msg_data.svtype, msg_data.svid, msg_data.uuid, json_string);
        }
    } while(false);
}

void ActionNotify::OnAccountGet(std::int32_t err_code, Account* pAccount, std::string&& trans)
{
    StreamData stream_data(std::move(trans));
    StreamDataReader reader(stream_data);
    std::uint16_t svtype = reader.ReadShort();
    std::uint32_t svid = reader.ReadInt();
    std::uint32_t uuid = reader.ReadInt();
    std::uint32_t uid = reader.ReadInt();
    std::string json_string = reader.ReadString();
    agency_event_api::NotifyReq req;
    do
    {
        if (err_code != 0)
        {
            log_error("get agency info failed,uid:%u,err_code:%d", uid, err_code);
            break;
        }
        if (pAccount == nullptr)
        {
            log_error("agency is nullptr,uid:%u,err_code:%d", uid, err_code);
            break;
        }
        Json::Value data_json;
        if (!CTools::FromStr(data_json, json_string))
        {
            log_error("json parser failed, body:%s", json_string.c_str());
            break;
        }

        Json::Value username_json;
        username_json.append(pAccount->username);
        data_json["usernameArr"] = username_json;
        json_string = CTools::ToStr(data_json);
        log_debug("json_string = %s", json_string.c_str());
    
       OnAgencyEventGetInc(pAccount->agencyid, svtype, svid, uuid, json_string);
    } while(false);
}

void ActionNotify::OnAgencyEventGetInc(std::uint32_t agencyid, std::uint16_t svtype, std::uint32_t svid, std::uint32_t uuid,  const std::string& notify_string)
{
    stAgencyEvent* st_agencyevent = AgencyEventMgr::Instance()->Get(agencyid);
    if (st_agencyevent != nullptr)
    {
        Request(*st_agencyevent, svtype, svid, uuid, notify_string);
    }
    else
    {
        StreamData stream_data;
        StreamDataWriter writer(stream_data);
        writer.WriteShort(svtype);
        writer.WriteInt(svid);
        writer.WriteInt(uuid);
        writer.WriteInt(agencyid);
        writer.WriteString(notify_string);

        if (!AgencyEventService::Instance()->HandleGetAgencyEvent(agencyid, std::move(stream_data.Data()), AgencyEventService::NOTIFY))
        {
            log_error("HandleGetAgencyEvent failed,agencyid:%u", agencyid);
            return;
        }
    }
}
void ActionNotify::OnAgencyEventGet(std::int32_t err_code, stAgencyEvent* agencyevent, std::string&& trans)
{
    StreamData stream_data(std::move(trans));
    StreamDataReader reader(stream_data);
    std::uint16_t svtype = reader.ReadShort();
    std::uint32_t svid = reader.ReadInt();
    std::uint32_t uuid = reader.ReadInt();
    std::uint32_t agencyId = reader.ReadInt();
    std::string json_string = reader.ReadString();
    agency_event_api::NotifyReq req;
    do
    {
        if (err_code != 0)
        {
            log_error("get agency info failed,agencyid:%u,err_code:%d", agencyId, err_code);
            break;
        }
        if (agencyevent == nullptr)
        {
            log_error("agency is nullptr,agencyid:%u,err_code:%d", agencyId, err_code);
            break;
        }
    
        Request(*agencyevent, svtype, svid, uuid, json_string);
        return;
    } while(false);
}


int ActionNotify::CheckData(const int type, Json::Value& data)
{
    if (type != agency_event_api::NOTIFY_TIP_GAME_NOTIFY)
    {
        return 0;
    }
    Json::Value data_json;
    if (!CTools::FromStr(data_json, data.asString()))
    {
        log_error("json parser failed, body:%s", data.asString().c_str());
        return agency_api::InputParamErr;
    }
    if (data_json.isMember("trigger_scen_list") == false || data_json["trigger_scen_list"].isArray() == false ||
        data_json.isMember("title") == false || data_json.isMember("content") == false || data_json.isMember("game") == false || 
        data_json.isMember("pic") == false || data_json.isMember("button_text") == false || data_json.isMember("jump_type") == false ||
        data_json.isMember("button_fuc") == false || data_json.isMember("jump_params") == false || data_json.isMember("priority") == false || data_json.isMember("level") == false)
    {
        log_error("LoadConfig err cfg param lose!");
        return agency_api::InputParamErr;
    }
    if (data_json["jump_type"].isString() == false || data_json["jump_params"].isString() == false)
    {
        log_error("jump_type or jump_params is not string!");
        return agency_api::InputParamErr;
    }
    std::string jump_type = data_json["jump_type"].asString();
    std::string jump_param_str = data_json["jump_params"].asString();
    
    Json::Value jump_params;
    if (!CTools::FromStr(jump_params, data_json["jump_params"].asString()))
    {
        log_error("json parser failed, body:%s", data_json["jump_params"].asString().c_str());
        return agency_api::InputParamErr;
    }
    if (jump_type == "match")
    {
        if (jump_params.isMember("subPage") == false || jump_params["subPage"].isInt() == false)
        {
            log_error("json parser failed, jump_type:%s, params:%s", jump_type.c_str(), data_json["jump_params"].asString().c_str());
            return agency_api::InputParamErr;
        }

        if (jump_params["subPage"].asInt() == agency_event_api::JUMP_TYPE_GAME && jump_params.isMember("matchInstanceId") == false)
        {
            log_error("json parser failed, jump_type:%s, params:%s", jump_type.c_str(), data_json["jump_params"].asString().c_str());
            return agency_api::InputParamErr;
        }  
        
        if (jump_params["subPage"].asInt() != agency_event_api::JUMP_TYPE_GAME && jump_params["subPage"].asInt() != agency_event_api::JUMP_TYPE_TICKET)
        {
            log_error("json parser failed, jump_type:%s, params:%s", jump_type.c_str(), data_json["jump_params"].asString().c_str());
            return agency_api::InputParamErr;
        }
    }
    else if (jump_type == "invite_task")
    {
        if (jump_params.isMember("subPage") == false || jump_params.isMember("taskId") == false || jump_params["subPage"].isInt() == false || jump_params["subPage"].asInt() != agency_event_api::JUMP_TYPE_INVITE)
        {
            log_error("json parser failed, jump_type:%s, params:%s", jump_type.c_str(), data_json["jump_params"].asString().c_str());
            return agency_api::InputParamErr;
        }
    }

    data_json["access"] = "kb";
    data = CTools::ToStr(data_json);
    return 0;
}

void ActionNotify::Request(const stAgencyEvent& agencyevent, std::uint16_t svtype, std::uint32_t svid, std::uint32_t uuid,  const std::string& notify_string)
{
    log_debug("body:%s", notify_string.c_str());
    do
    {
        Json::Value notify_json;
        if (!CTools::FromStr(notify_json, notify_string))
        {
            log_error("json parser failed, body:%s", notify_string.c_str());
            break;
        }
        if (agencyevent.state != 1)
        {
            log_error("agency state not valid, %s", agencyevent.ToString().c_str());
            break;
        }
        if (notify_json.isMember("game") == false || notify_json["game"].isUInt() == false)
        {
            log_error("notify_json.isMember[game] == false || notify_json[game].isUInt == false");
            break;
        }
        if (notify_json.isMember("type") == false || notify_json["type"].isUInt() == false)
        {
            log_error("notify_json.isMember[type] == false || notify_json[type].isUInt == false");
            break;
        }
        if (notify_json.isMember("data") == false || notify_json["data"].isString()== false)
        {
            log_error("notify_json.isMember[data] == false || notify_json[data].isString == false");
            break;
        }
        
        if (notify_json.isMember("usernameArr") == false || notify_json["usernameArr"].isArray() == false)
        {
            log_error("notify_json.isMember[usernameArr] == false || notify_json[usernameArr].isString == false");
            break;
        }

        // if (agencyevent.gamelist.find(notify_json["game"].asUInt()) == agencyevent.gamelist.end())
        // {
        //     log_error("game:%u not support, %s", notify_json["game"].asUInt(), agencyevent.ToString().c_str());
        //     break;
        // }

        int err = CheckData(notify_json["type"].asInt(), notify_json["data"]);
        if (err != 0)
        {
            log_error("type:%d, data:%s", notify_json["type"].asInt(), notify_json["data"].asString().c_str());
            break;
        }
        
        Json::Value usernamearr_json = notify_json["usernameArr"];
        
        bool bNeedSplit = notify_json["usernameArr"].size() > NOTIFY_MAX_USER_NUM ? true : false;
        int send_idx = 0;
        do
        {
            if (bNeedSplit)
            {
                notify_json["usernameArr"].clear();
                for (size_t i = 0; i < NOTIFY_MAX_USER_NUM && send_idx < usernamearr_json.size(); i++, send_idx++)
                {
                    notify_json["usernameArr"].append(usernamearr_json[send_idx].asString());
                }
            }

            log_debug("total = %d, send_idx = %d bNeedSplit = %d total = %d", notify_json["usernameArr"].size(), send_idx, bNeedSplit, usernamearr_json.size());
            
            std::uint64_t reqtime = CTools::GetUnixTime();
            notify_json["reqId"] = GenTransId();
            notify_json["reqtime"] = Json::Int64(reqtime);

            std::string url = agencyevent.call_url + "/Notify";

            std::string json_string = CTools::ToStr(notify_json);
            std::uint32_t event_id = 0;
            // 请求http网络
            if (!Ctx.msg_router.sendHttpPOST(url, json_string, http_json_heads, event_id) || (event_id == 0))
            {
                log_error("net post failed,url:%s,param:%s", url.c_str(), json_string.c_str());
                break;
            }
            // 复制一份请求数据   
            //auto req_copy = std::make_shared<agency_event_api::NotifyReq>(notifyReq);
            // 添加回调监听
            Ctx.msg_router.AddCurlEvent(event_id, [
                url=std::move(url), json_string= std::move(json_string), reqtime] (std::string& body, bool is_ok){
                Json::Value http_resp;
                
                std::uint64_t resptime = CTools::GetUnixTime();

                log_info("url:%s,req:%s,resp:%s,reqtime:%llu,resptime:%llu", 
                    url.c_str(), json_string.c_str(), body.c_str(), reqtime, resptime);

                do
                {
                    // 网络错误
                    if (!is_ok)
                    {
                        log_error("time out,url:%s,param:%s", url.c_str(), json_string.c_str());
                        break;
                    }
                    
                    // 解析返回格式
                    if (!CTools::FromStr(http_resp, body))
                    {
                        log_error("resp from json failed, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                        break;
                    }
                    if (!http_resp.isMember("errorCode") || !http_resp["errorCode"].isInt())
                    {
                        log_error("response param invalid, body:%s ,url:%s,param:%s", body.c_str(), url.c_str(), json_string.c_str());
                        break;
                    }

                } while (false); 
            });

        } while (bNeedSplit && send_idx < usernamearr_json.size());
        
    } while(false);
}
